/* =========================================
 *      好友管理子服务的客户端测试搭建 
 * =========================================*/

#include "etcd.hpp"
#include "channel.hpp"
#include "base.pb.h"
#include "friend.pb.h"
#include "utils.hpp"
#include <boost/date_time/posix_time/conversion.hpp>
#include <boost/date_time/posix_time/time_formatters.hpp>
#include <boost/date_time/posix_time/time_parsers.hpp>
#include <brpc/controller.h>
#include <cstdint>
#include <gflags/gflags.h>
#include <gtest/gtest.h>
#include <iostream>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

DEFINE_bool(run_mode, false, "程序的运行模式: false-调试 true-发布");
DEFINE_string(log_file, "", "指定日志的输出文件");
DEFINE_int32(log_level, 0, "指定日志输出等级");

DEFINE_string(etcd_host, "http://127.0.0.1:2379", "服务注册中心地址");
DEFINE_string(base_service, "/service", "服务监控根目录");
DEFINE_string(friend_service, "/service/friend_service", "当前监控的服务");

shared::infra::RpcServiceManagerPtr rpcServiceMgr;

std::vector<std::pair<std::string, std::string>> friendApplyList = {
    {"uid2", "uid1"},
    {"uid3", "uid1"},
    {"uid4", "uid1"}
};

std::vector<std::string> newSessionIdList;

// uid2 uid3 uid4 都向 uid1 发起好友申请
TEST(FriendSeriveceTest, FriendApply)
{
    auto channel = rpcServiceMgr->choose(FLAGS_friend_service); 
    ASSERT_TRUE(channel);

    im_proto::FriendAddReq req;

    for(auto& [reqId, recvId] : friendApplyList) {
        req.set_request_id(shared::Uuid::createUuid());
        req.set_req_user_id(reqId);
        req.set_recv_user_id(recvId);

        brpc::Controller controller;
        im_proto::FriendAddRsp resp;
        im_proto::FriendService_Stub stub(channel.get());
        stub.FriendAdd(&controller, &req, &resp, nullptr);
        ASSERT_FALSE(controller.Failed());
        ASSERT_TRUE(resp.success());
    }
}

// 获取 uid1 的好友申请列表, 预期结果有3个 --- uid2 uid3 uid4
TEST(FriendSeriveceTest, GetApplyList)
{
    auto channel = rpcServiceMgr->choose(FLAGS_friend_service); 
    ASSERT_TRUE(channel);

    im_proto::GetPendingFriendEventListReq req;
    req.set_request_id(shared::Uuid::createUuid());
    req.set_user_id("uid1");

    brpc::Controller controller;
    im_proto::GetPendingFriendEventListRsp resp;
    im_proto::FriendService_Stub stub(channel.get());
    stub.GetPendingFriendEventList(&controller, &req, &resp, nullptr);
    ASSERT_FALSE(controller.Failed());
    ASSERT_TRUE(resp.success());

    auto applyList = resp.event();
    ASSERT_EQ(applyList.size(), 3);
    for(int i = 0; i < applyList.size(); ++i) {
        auto& sender = applyList[i].sender();
        std::cout << "--------- GetApplyList ----------" << '\n';
        std::cout << sender.user_id() << '\n';
        std::cout << sender.nickname() << '\n';
        std::cout << sender.description() << '\n';
        std::cout << sender.phone() << '\n';
        std::cout << sender.avatar() << '\n';
    }
}

// uid1 对来自 uid2 uid3 uid4 好友申请进行处理
TEST(FriendSeriveceTest, FriendAddProcess)
{
    auto channel = rpcServiceMgr->choose(FLAGS_friend_service); 
    ASSERT_TRUE(channel);

    im_proto::FriendAddProcessReq req;
    req.set_request_id(shared::Uuid::createUuid());
    for(int i = 0; i < friendApplyList.size(); ++i) {
        bool f = i % 2 == 0;     // 拒绝第偶数个用户的申请
        req.set_agree(f);
        req.set_req_user_id(friendApplyList[i].first);
        req.set_recv_user_id(friendApplyList[i].second);

        brpc::Controller controller;
        im_proto::FriendAddProcessRsp resp;
        im_proto::FriendService_Stub stub(channel.get());
        stub.FriendAddProcess(&controller, &req, &resp, nullptr);
        ASSERT_FALSE(controller.Failed());
        ASSERT_TRUE(resp.success());
        if(f) {
            std::cout << "--------- FriendAddProcess ----------" << '\n';
            std::cout << resp.new_session_id() << '\n';
            newSessionIdList.emplace_back(resp.new_session_id());
        }
    }
}

// uid1的好友(uid2, uid4) 搜索用户(uid3)
// | 3 | uid3 | 小帅  | 159357  | 16522227777 | 我是Bond, GG Bond!  | a993-fd6af1eb-02 |
TEST(FriendSeriveceTest, FriendSearch)
{
    auto channel = rpcServiceMgr->choose(FLAGS_friend_service); 
    ASSERT_TRUE(channel);

    im_proto::FriendSearchReq req;
    req.set_request_id(shared::Uuid::createUuid());
    req.set_user_id("uid1");
    req.set_search_key("小");

    brpc::Controller controller;
    im_proto::FriendSearchRsp resp;
    im_proto::FriendService_Stub stub(channel.get());
    stub.FriendSearch(&controller, &req, &resp, nullptr);
    ASSERT_FALSE(controller.Failed());
    ASSERT_TRUE(resp.success());

    auto searchUsers = resp.user_info();
    ASSERT_EQ(searchUsers.size(), 1);
    for(auto& user : searchUsers) {
        std::cout << "--------- FriendSearch ----------" << '\n';
        std::cout << user.user_id() << '\n';
        std::cout << user.nickname() << '\n';
        std::cout << user.description() << '\n';
        std::cout << user.phone() << '\n';
        std::cout << user.avatar() << '\n';
    }
}

// 获取 uid1 的好友列表 -- uid2 uid4
TEST(FriendSeriveceTest, GetFriendList)
{
    auto channel = rpcServiceMgr->choose(FLAGS_friend_service); 
    ASSERT_TRUE(channel);

    im_proto::GetFriendListReq req;
    req.set_request_id(shared::Uuid::createUuid());
    req.set_user_id("uid1");

    brpc::Controller controller;
    im_proto::GetFriendListRsp resp;
    im_proto::FriendService_Stub stub(channel.get());
    stub.GetFriendList(&controller, &req, &resp, nullptr);
    ASSERT_FALSE(controller.Failed());
    ASSERT_TRUE(resp.success());

    auto searchUsers = resp.friend_list();
    ASSERT_EQ(searchUsers.size(), 2);
    for(auto& user : searchUsers) {
        std::cout << "--------- GetFriendList ----------" << '\n';
        std::cout << user.user_id() << '\n';
        std::cout << user.nickname() << '\n';
        std::cout << user.description() << '\n';
        std::cout << user.phone() << '\n';
        std::cout << user.avatar() << '\n';
    }
}

// uid1 删除它的好友 uid4
TEST(FriendSeriveceTest, FriendRemove)
{
    auto channel = rpcServiceMgr->choose(FLAGS_friend_service); 
    ASSERT_TRUE(channel);

    im_proto::FriendRemoveReq req;
    req.set_request_id(shared::Uuid::createUuid());
    req.set_req_user_id("uid1");
    req.set_recv_user_id("uid4");

    brpc::Controller controller;
    im_proto::FriendRemoveRsp resp;
    im_proto::FriendService_Stub stub(channel.get());
    stub.FriendRemove(&controller, &req, &resp, nullptr);
    ASSERT_FALSE(controller.Failed());
    ASSERT_TRUE(resp.success());
}

// 创建一个 uid1 uid2 uid3 uid4 的群聊
// 获取群聊成员验证
TEST(FriendSeriveceTest, ChatSessionCreateAndGetMember)
{
    auto channel = rpcServiceMgr->choose(FLAGS_friend_service); 
    ASSERT_TRUE(channel);

    std::vector<std::string> users = {"uid1", "uid2", "uid3", "uid4"};
    
    im_proto::ChatSessionCreateReq req;
    req.set_request_id(shared::Uuid::createUuid());
    req.set_chat_session_name("007组织");
    for(auto& user : users) {
        req.add_member_id_list(user);
    }

    brpc::Controller controller;
    im_proto::ChatSessionCreateRsp resp;
    im_proto::FriendService_Stub stub(channel.get());
    stub.ChatSessionCreate(&controller, &req, &resp, nullptr);
    ASSERT_FALSE(controller.Failed());
    ASSERT_TRUE(resp.success());

    auto chatSessionInfo = resp.chat_session_info();
    ASSERT_EQ(chatSessionInfo.chat_session_name(), "007组织");
    std::cout << "--------- GroupChatSessionCreate ----------" << '\n';
    std::cout << chatSessionInfo.chat_session_id() << '\n';
    std::cout << chatSessionInfo.chat_session_name() << '\n';


    im_proto::GetChatSessionMemberReq req2;
    req2.set_request_id(shared::Uuid::createUuid());
    req2.set_chat_session_id(chatSessionInfo.chat_session_id());

    brpc::Controller controller2;
    im_proto::GetChatSessionMemberRsp resp2;
    im_proto::FriendService_Stub stub2(channel.get());
    stub2.GetChatSessionMember(&controller2, &req2, &resp2, nullptr);
    ASSERT_FALSE(controller2.Failed());
    ASSERT_TRUE(resp2.success());
    auto members = resp2.member_info_list();
    for(int i = 0; i < members.size(); ++i) {
        ASSERT_EQ(members[i].user_id(), users[i]);
        std::cout << "--------- GetChatSessionMember ----------" << '\n';
        std::cout << members[i].user_id() << '\n';
        std::cout << members[i].nickname() << '\n';
        std::cout << members[i].phone() << '\n';
        std::cout << members[i].description() << '\n';
        std::cout << members[i].avatar() << '\n';
    }
}

// 获取 uid1 用户的会话列表
TEST(FriendSeriveceTest, GetChatSessionList)
{
    auto channel = rpcServiceMgr->choose(FLAGS_friend_service); 
    ASSERT_TRUE(channel);

    im_proto::GetChatSessionListReq req;
    req.set_request_id(shared::Uuid::createUuid());
    req.set_user_id("uid1");

    brpc::Controller controller;
    im_proto::GetChatSessionListRsp resp;
    im_proto::FriendService_Stub stub(channel.get());
    stub.GetChatSessionList(&controller, &req, &resp, nullptr);
    ASSERT_FALSE(controller.Failed());
    ASSERT_TRUE(resp.success());

    auto& chatSessionInfoList = resp.chat_session_info_list();
    ASSERT_EQ(chatSessionInfoList.size(), 2);
    for(auto& csInfo : chatSessionInfoList) {
        std::cout << "--------- GetChatSessionList ----------" << '\n';
        std::cout << csInfo.chat_session_id() << '\n';
        std::cout << csInfo.chat_session_name() << '\n';
        std::cout << csInfo.single_chat_friend_id() << '\n';
        std::cout << csInfo.avatar() << '\n';
        if(csInfo.prev_message().has_message()) {
            ASSERT_EQ(csInfo.chat_session_id(), csInfo.prev_message().chat_session_id());
            ASSERT_NE(csInfo.avatar(), csInfo.prev_message().sender().avatar());
            std::cout << "-- prevMsg --" << '\n';
            std::cout << csInfo.prev_message().message_id() << '\n';
            std::cout << csInfo.prev_message().chat_session_id() << '\n';
            std::cout << csInfo.prev_message().timestamp() << '\n';
            std::cout << csInfo.prev_message().sender().user_id() << '\n';
            std::cout << csInfo.prev_message().sender().nickname() << '\n';
            std::cout << csInfo.prev_message().sender().avatar() << '\n';
            std::cout << csInfo.prev_message().message().file_message().file_name() << '\n';
            std::cout << csInfo.prev_message().message().file_message().file_contents() << '\n';
        }
    }   
}


int main(int argc, char* argv[])
{
    testing::InitGoogleTest(&argc, argv);
    google::ParseCommandLineFlags(&argc, &argv, true);
    shared::init_logger(FLAGS_run_mode, FLAGS_log_file, FLAGS_log_level);

    // 1.构造rpc服务管理对象
    rpcServiceMgr = std::make_shared<shared::infra::RpcServiceManager>();
    rpcServiceMgr->declared(FLAGS_friend_service);   
    auto putCb = std::bind(
        &shared::infra::RpcServiceManager::onServiceOnline, rpcServiceMgr.get(), std::placeholders::_1, std::placeholders::_2
    );
    auto delCb = std::bind(
        &shared::infra::RpcServiceManager::onServiceOffline, rpcServiceMgr.get(), std::placeholders::_1, std::placeholders::_2
    );

    // 2.构造服务发现对象
    shared::infra::DiscoveryPtr client = std::make_shared<shared::infra::Discovery>(
        FLAGS_etcd_host, FLAGS_base_service, putCb, delCb
    );

    return RUN_ALL_TESTS();
}